/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * bocciawii
 * Copyright (C) Grupo de trabajo ULE 2010 <ulewii@googlegroups.com>
 * 
 * teclado is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * teclado is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _ELEMENTO_H_
#define _ELEMENTO_H_
#include <FTGL/ftgl.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <iostream>
#include "rutas.h"

#define IMG_ALIGN_LEFT 1
#define IMG_ALIGN_ABOVE 2
#define IMG_ALIGN_RIGHT 3
#define IMG_ALIGN_BELOW 4
#define IMG_ALIGN_CENTER 5 // Sólo para las imágenes de fondo
#define IMG_ALIGN_BELOW_RIGHT 6 // Sólo para las imágenes de fondo
#define IMG_ALIGN_ABOVE_RIGHT 7 // Sólo para las imágenes de fondo

/**
 * @brief Estructura para determinar posición en pantalla de una imagen
 *
 * Almacena los datos de una imagen en el momento de carga.
 * En el momento de <code>Elemento::Pack()</code> calcula los datos absolutos con 
 * coordenadas pantalla.
 */
typedef struct
{
	/// Coordenada de pantalla
	int x_inicio;
	/// Coordenada de pantalla
	int y_inicio;
	/// Coordenada de pantalla
	int x_final;
	/// Coordenada de pantalla
	int y_final;
	/// Valor para cómputo
	int alignment;
	/// Valor para cómputo
	int ancho;
	/// Valor para cómputo
	int alto;
} img_alloc;

/**
 * @brief Estructura para determinar posición en pantalla de un texto
 *
 * Almacena los datos de un mensaje
 * En el momento de <code>Elemento::Pack()</code> calcula los datos absolutos con 
 * coordenadas pantalla.
 * 
 */
typedef struct
{
	/// Coordenada de pantalla. Coordenada X de la baseline del primer glifo.
	int pen_x;
	/// Coordenada de pantalla. Coordenada Y de la baseline de la primera línea de glifos.
	int pen_y;
	/// Valor para cómputo
	int ancho;
	/// Valor para cómputo
	int alto;
} text_alloc;


/**
 * @brief Estructura para determinar posición en pantalla de una
 *
 * Almacena los datos de una barra
 * En el momento de <code>Elemento::Pack()</code> calcula los datos absolutos con 
 * coordenadas pantalla.
 * 
 */
typedef struct
{
	/// Coordenada de pantalla
	int x_inicio;
	/// Coordenada de pantalla
	int y_inicio;
	/// Coordenada de pantalla
	int x_final;
	/// Coordenada de pantalla
	int y_final;
	/// Valor para cómputo
	int ancho;
	/// Valor para cómputo
	int alto;
} bar_alloc;



/**
 * @brief Base virtual de los elementos planos del motor gráfico.
 *
 * Estos elementos, de momento, sólo soportan barras y mensajes.
 *
 * Está inspirado (un poco, y al menos en nuestra cabeza) en GTK, aunque como
 * veremos en otras clases, el proceso de añadir  a contenedores se realiza al revés
 *
 * Todo elemento final podrá componerse de una barra y una imagen, de una imagen exclusivamente,
 * o de un mensaje y una imagen.
 *
 * Las imágenes son un un QUAD con textura (tranparente o no). La textura se encuentra en GL_REPLACE
 * y no es necesario invertirlas (como ocurría con elemento_estacionario) ya que el contexto
 * que hemos elegido para el dibujado 2D ajusta las coordenadas de pantalla a las 
 * mismas que SDL, esto es: generamos una matrix 2D con gluOrtho() que cambia las 
 * coordenadas de pantalla al revés que el sistema de OpenGL, así que al dibujar las texturas
 * que SDL carga también al revés que OpenGL, éstas serán dibujadas correctamente.
 * 
 * De nuevo, aunque nuestro contexto esté al revés, el texto seguirá dibujándose
 * correctamente porque se trata de fuentes rasterizadas, para las que OpenGL utiliza
 * un sistema de coordenadas absolutas de viewport.
 *
 * Para hacer el motor más "eficiente", se debería haber implementado otro struct de tamaño
 * que contara con el tamaño de ambos elementos (imagen + widget) e incluírlo aquí, 
 * ya que sería común a todos los widgets, y así implementar aquí también los procedimientos
 * de obtención de tamaños (actualmente es el propio procedimiento el que devuelve el tamaño
 * calculando el de la imagen y el widget por separado)
 */
class Elemento
{
public:
	/**
	 * @brief Constructor del elemento virtual
	 * 
	 * Se le asignará una ID única en todo su super-container <code>ScreenLayout</code> o
	 * <code>MenuLayout</code>
	 */
	Elemento(std::string id);
	virtual ~Elemento();

	
	// Comunes implementadas aquí
	/**
	 * @brief Asigna una imagen al elemento
	 *
	 * Éste es un proceso independiente a si el elemento es una barra o es un mensaje
	 * Por esto se puede implementar en la base virtual. Actualmente los únicos tipos
	 * de imágenes soportados por el motor son, al igual que con <code>ElementoEstacionario</code>
	 * .PNG con o sin transparencia.
	 * 
	 * @param nombre Nombre del archivo .PNG (la ruta se determina por <code>rutas.h</code>)
	 * @param tam_x El ancho de la imagen (-1, por defecto, para utilizar la imagen al completo)
	 * @param tam_y El alto de la imagen (-1, por defecto, para utilizar la imagen al completo)
	 * @param img_align IMG_ALIGN_LEFT (por omisión) ó IMG_ALIGN_RIGHT ó IMG_ALIGN_ABOVE ó IMG_ALIGN_LEFT
	 */
	void SetImage(std::string nombre, 
						  int tam_x = -1, 
						  int tam_y = -1,						   
						  int img_align = IMG_ALIGN_LEFT);

	
	/**
	 * @brief Asigna un identificador de textura de OpenGL como imagen
	 *
	 * Éste es un proceso independiente a si el elemento es una barra o es un mensaje
	 * Por esto se puede implementar en la base virtual. Actualmente los únicos tipos
	 * de imágenes soportados por el motor son, al igual que con <code>ElementoEstacionario</code>
	 * .PNG con o sin transparencia.
	 * 
	 * @param nombre Nombre del archivo .PNG (la ruta se determina por <code>rutas.h</code>)
	 * @param tam_x El ancho de la imagen (es obligatorio especificarlo al asignar un índice de OpenGL)
	 * @param tam_y El alto de la imagen (es obligatorio especificarlo al asignar un índice de OpenGL)
	 * @param img_align IMG_ALIGN_LEFT (por omisión) ó IMG_ALIGN_RIGHT ó IMG_ALIGN_ABOVE ó IMG_ALIGN_LEFT
	 */
	void SetImage(GLuint id_gl, 
						  int tam_x, 
						  int tam_y,						   
						  int img_align = IMG_ALIGN_LEFT);

	/**
	 * @brief Getter para el identificador de imagen
	 *
	 * Devolverá el identificador de OpenGL para la textura que será nuestra imagen
	 * @return GLuint con el índice de textura
	 */
	inline GLuint GetImage()
	{	return _image;    }
	

	/**
	 * @brief Getter para el string identificador
	 *
	 * Devolverá el identificador del elemento. Se sugiere que sea único no sólo en
	 *  contenedor inmediato, sino en todo el supercontainer
	 *
	 * @return string con el id del elemento
	 */
	inline std::string GetID()
	{   return _id;	 }

	virtual void SetFGColor(float* color);
	virtual void SetBGColor(float* color);
	// Comunes implementadas en cada subclase
	virtual void SetSize(int size);
	virtual int* GetNeededSpace();
	virtual int* GetScreenCoords();
	virtual void Pack(int centro_x, int centro_y);
	virtual void Dibujar();

	// Mensajes
	virtual void SetText(std::string text);
	virtual void SetText(int text);
	virtual void SetText(float text);
	virtual void SetTextAlign(FTGL::TextAlignment align, int line_lenght = -1);

	// Barras
	virtual void SetPercent(int percent);
	
protected:
	/// Identificador del objeto
	std::string _id;

	/// Identificador GL de la imagen
	GLuint _image;

	/// Texto a mostrar en caso de ser un texto
	std::string _text;

	/// Posición de la imagen, y su tamaño
	img_alloc _posImg;

	/// Espaciado entre texto e imagen.
	int _spacing;

private:

	SDL_Surface* LoadPNG(std::string ruta);

	
};

#endif // _ELEMENTO_H_
